﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using HAC;
//HAC_Clustering.exe {in:GenericTSV|CosmosPath:similarity_data} {out:GenericTSV:clustering_result} (similarity_threshold:double,0.1,1.0:default,0.3) (maxPairs:int,0,:default,0) (indexOfItem1:int,0,:default,0) (indexOfItem2:int,0,:default,1) (indexOfSimilarity:int,0,:default,2) (MinSimilarity:float,0,1:default,0) (OutputFormat:enum,folded,unfolded) (ShortCutSimilarity:float,0,1:default,0.1) (DebugOutputInterval:int,1,100000:default,200)

namespace MyDomainClustering
{
    public class Program
    {
        
        static void Main(string[] args)
        {
            DateTime startTime = System.DateTime.Now;

            Program program = new Program();
            //string similarityData = @"D:\Pop Team Work\Bing Job Output\Src-Src Pair Similarity Analysis\100_srcsrcpair_similarity_above8_with_spam.txt";
            //string similarityData = @"D:\Pop Team Work\Bing Job Output\Src-Src Pair Similarity Analysis\500_srcsrcpair_similarity_above8.txt";
            //string similarityData = @"D:\Pop Team Work\Bing Job Output\Src-Src Pair Similarity Analysis\500_srcsrcpair_similarity_above6.txt";
            //string similarityData = @"D:\Pop Team Work\Bing Job Output\Src-Src Pair Similarity Analysis\500_srcsrcpair_similarity_above8_cut09.txt";
            string similarityData = args[0];
            //string similarityData = @"M:\VS Temp Data\simulated_similarity_data_big.txt";
            //double similarityThreshold = 0.6;
            double similarityThreshold = Convert.ToDouble(args[2]);
            long maxPairs = Convert.ToInt64(args[3]);
            //int maxPairs = 0;
            if (maxPairs == 0)
            {
                maxPairs = long.MaxValue;
            }
            int indexOfItem1 = Convert.ToInt32(args[4]);
            int indexOfItem2 = Convert.ToInt32(args[5]);
            int indexOfSimilarity = Convert.ToInt32(args[6]);
            // indexOfItem1 = Convert.ToInt32(0);
            //int indexOfItem2 = Convert.ToInt32(1);
            //int indexOfSimilarity = Convert.ToInt32(5);

            Clustering clustering = new Clustering();
            program.prepareData(clustering, similarityData, similarityThreshold, maxPairs, indexOfItem1, indexOfItem2, indexOfSimilarity);

            float Max_Distance = 1;
            if (args.Length >= 8)
            {
                Max_Distance = 1-(float)Convert.ToDouble(args[7]);
            }

            float ShortCutDistance = 1;
            if (args.Length >= 10)
            {
                ShortCutDistance = 1-(float)Convert.ToDouble(args[9]);
            }

            int DebugOutputInterval = 200;
            if (args.Length >= 11)
            {
                DebugOutputInterval = Convert.ToInt32(args[10]);
            }

            Console.WriteLine("Running with params: Max_Distance-{0}, ShortCutDistance-{1}, DebugOutputInterval-{2}", Max_Distance, ShortCutDistance, DebugOutputInterval);

            HAC.Cluster[] clusters = clustering.doCluster(1, Max_Distance, ShortCutDistance, DebugOutputInterval);

            //string outputPath = @"D:\Pop Team Work\Bing Job Output\Src-Src Pair Similarity Analysis\Clustering Results\clusters_100_srcsrcpair_similarity_above8_with_spam.txt";
            //string outputPath = @"D:\Pop Team Work\Bing Job Output\Src-Src Pair Similarity Analysis\Clustering Results\clusters_500_srcsrcpair_similarity_above8_full.txt";
            //string outputPath = @"D:\Pop Team Work\Bing Job Output\Src-Src Pair Similarity Analysis\Clustering Results\clusters_500_srcsrcpair_similarity_above6_full.txt";
            //string outputPath = @"M:\VS Temp Data\clusters_big.txt";
            string outputPath = args[1];
            string OutputFormat = "folded";
            if (args.Length >= 9)
            {
                OutputFormat = args[8].Trim();
            }
            //string outputPath = @"D:\Pop Team Work\Bing Job Output\Src-Src Pair Similarity Analysis\Clustering Results\clusters_500_srcsrcpair_similarity_above8_cut09.txt";
            program.outputResult(outputPath, clusters, OutputFormat);
            
            DateTime endTime = System.DateTime.Now;
            Console.WriteLine("Time cost:"+(endTime-startTime));
        }

        public void outputResult(string outputPath, HAC.Cluster[] clusters, string OutputFormat)
        {
            if (File.Exists(outputPath))
            {
                File.Delete(outputPath);
            }
            StreamWriter writer = File.CreateText(outputPath);

            if (OutputFormat.Equals("folded"))
            {
                outputResult_folded(writer, clusters);
            }
            else
            {
                outputResult_unfolded(writer, clusters);
            }
            
            writer.Close();
        }
        private void outputResult_folded(StreamWriter writer, HAC.Cluster[] clusters)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < clusters.Count(); i++)
            {
                bool first = true;
                sb.Clear();
                sb.Append(clusters[i].elementNumber() + "\t");
                sb.Append((1 - clusters[i].Avg_distance) + "\t" + (1 - clusters[i].Min_distance) + "\t" + (1 - clusters[i].Max_distance) + "\t");
                foreach (Element e in clusters[i])
                {
                    if (!first)
                    {
                        sb.Append(",");
                    }
                    else
                    {
                        first = false;
                    }

                    sb.Append(e.Id);
                }
                writer.WriteLine(sb.ToString());
            }
        }
        private void outputResult_unfolded(StreamWriter writer, HAC.Cluster[] clusters)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < clusters.Count(); i++)
            {
                foreach (Element e in clusters[i])
                {
                    sb.Clear();
                    sb.Append(i + "\t" + clusters[i].elementNumber() + "\t");
                    sb.Append((1 - clusters[i].Avg_distance) + "\t" + (1 - clusters[i].Min_distance) + "\t" + (1 - clusters[i].Max_distance) + "\t");
                    sb.Append(e.Id);
                    writer.WriteLine(sb.ToString());
                }
            }
        }
        private void prepareData(Clustering clustering, string similarityData, double threshold, long max_pairs, int indexOfItem1, int indexOfItem2, int indexOfSimilarity)
        {
            StreamReader reader = File.OpenText(similarityData);
            string line = null;
            long pairCount = 0;
            while ((line = reader.ReadLine()) != null && pairCount < max_pairs)
            {               
                Pair pairData = getPairData(line, indexOfItem1, indexOfItem2, indexOfSimilarity);
                if (pairData.similarity >= threshold)
                {
                    pairCount++;
                    clustering.addNewSimilarityPair(pairData);
                    //Console.WriteLine(pairCount);
                }
            }
            Console.WriteLine("{0} lines were read", pairCount);
            reader.Close();
        }
        private Pair getPairData(string line, int indexOfItem1, int indexOfItem2, int indexOfSimilarity)
        {
            char delimiter = '\t';
            string[] columns = line.Split(delimiter);
            Pair pair = new Pair(columns[indexOfItem1], columns[indexOfItem2], (float)Convert.ToDouble(columns[indexOfSimilarity]));
            return pair;
        }
    }
}
